package com.tbit.uqbike.compalint.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tbit.common.config.OssDefaultConfig;
import com.tbit.config.payConfig.WxMchConfig;
import com.tbit.uqbike.compalint.enums.ComplaintStatusEnum;
import com.tbit.uqbike.compalint.enums.PlatformEnum;
import com.tbit.uqbike.compalint.mapper.ComplaintHistoryMapper;
import com.tbit.uqbike.compalint.mapper.ComplaintMapper;
import com.tbit.uqbike.compalint.param.*;
import com.tbit.uqbike.compalint.service.base.AbstractComplaintService;
import com.tbit.uqbike.compalint.table.ComplaintDO;
import com.tbit.uqbike.compalint.table.ComplaintHistoryDO;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.WeixinPayConfig;
import com.tbit.uqbike.service.business.WeixinPayConfigService;
import com.tbit.uqbike.webmanager.util.HttpClientUtils;
import com.tbit.uqbike.webmanager.util.aliyun.OssFileUtils;
import com.tbit.utils.WxV3Utils;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.crypto.BadPaddingException;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 微信客诉api
 * 服务商
 *
 * @author <a href="mailto:zhang.zhiliang@tbit.com.cn">Zhang ZhiLiang</a>
 * @version 1.0
 * @see <a href="http://adsl1.tbit.com.cn:21490/pages/viewpage.action?pageId=82182491">订单号规范</a>
 * @since 2025/2/14
 */
@Slf4j
@Service(value = "WechatComplaintService")
public class WechatComplaintService extends AbstractComplaintService {

    // 微信基础域名
    private final String BASE_URL = "https://api.mch.weixin.qq.com";
    // 拉取客诉接口路径
    private final String PULL_COMPLAINT_URL = "/v3/merchant-service/complaints-v2";
    // 回复客诉接口路径
    private final String RESPONSE_COMPLAINT_URL = "/v3/merchant-service/complaints-v2/%s/response";
    // 反馈处理完成接口路径
    private final String COMPLETE_COMPLAINT_URL = "/v3/merchant-service/complaints-v2/%s/complete";
    // 协商历史接口路径
    private final String COMPLAINT_HISTORY_DETAIL = "/v3/merchant-service/complaints-v2/%s/negotiation-historys";
    // 获取客诉详情接口路径
    private final String COMPLAINT_DETAIL = "/v3/merchant-service/complaints-v2/%s";
    // 图片请求接口路径
    private final String COMPLAINT_PICTURE = "/v3/merchant-service/images/%s";

    private final WeixinPayConfigService weixinPayConfigService;
    private final WxMchConfig wxMchConfig;

    @Autowired
    public WechatComplaintService(ComplaintMapper complaintMapper, ComplaintHistoryMapper complaintHistoryMapper,
                                  OssDefaultConfig ossDefaultConfig, WeixinPayConfigService weixinPayConfigService, WxMchConfig wxMchConfig) {
        super(complaintMapper, complaintHistoryMapper, ossDefaultConfig);
        this.weixinPayConfigService = weixinPayConfigService;
        this.wxMchConfig = wxMchConfig;
    }

    /**
     * 微信客诉 - 回复用户留言api
     *
     * @param param 回复用户客诉留言参数
     * @return 是否成功
     */
    @Override
    public Boolean responseApi(ComplaintResponseParam param) {
        WeixinPayConfig weixinPayConfig = weixinPayConfigService.getByAccountId(param.getBrandId(), 2);
        if (Objects.isNull(weixinPayConfig)) {
            throw new BaseException(String.format("%s微信品牌配置为空，回复失败", param.getBrandId()));
        }
        String uri = String.format(RESPONSE_COMPLAINT_URL, param.getComplaintId());
        String bodyStr = getResponseParamBodyStr(weixinPayConfig.getPartner(), param.getContent());
        String authorization = null;
        try {
            authorization = getHttpAuthorization(uri, "POST", bodyStr);
        } catch (Exception e) {
            log.error("投诉单号{}签名生成失败", param.getComplaintId(), e);
            return false;
        }
        Map<String, Object> headerMap = getHeaderMap_Post(authorization);
        String url = String.format("%s%s", BASE_URL, uri);
        HttpClientUtils.httpPost(url, headerMap, bodyStr);
        return true;
    }

    /**
     * 微信客诉 - 拉取客诉最新状态
     *
     * @param param 客诉状态拉取参数
     * @return 格式化后的平台状态枚举
     */
    @Override
    public ComplaintStatusEnum getDetailApi(ComplaintVerifyParam param) {
        String uri = String.format(COMPLAINT_DETAIL, param.getComplaintId());
        String authorization = null;
        try {
            authorization = getHttpAuthorization(uri, "GET", "");
        } catch (Exception e) {
            log.error("投诉单号{}签名生成失败", param.getComplaintId(), e);
            return null;
        }
        Map<String, Object> headerMap = getHeaderMap_Get(authorization);
        String url = String.format("%s%s", BASE_URL, uri);
        String res = HttpClientUtils.httpGet(url, headerMap);
        JSONObject jsonObject = JSONObject.parseObject(res);
        return ComplaintStatusEnum.getComplaintEnumByWechat(jsonObject.getString("complaint_state"));
    }

    /**
     * 微信客诉 - 客诉协商历史查询
     *
     * @param param 客诉协商历史查询参数
     * @return 客诉协商历史
     */
    @Override
    public List<ComplaintHistoryDO> getHistoryDetailApi(ComplaintHistoryParam param) {
        String uri = String.format(COMPLAINT_HISTORY_DETAIL, param.getComplaintId());
        String authorization = null;
        try {
            authorization = getHttpAuthorization(uri, "GET", "");
        } catch (Exception e) {
            log.error("投诉单号{}签名生成失败", param.getComplaintId(), e);
            return new ArrayList<>();
        }
        Map<String, Object> headerMap = getHeaderMap_Get(authorization);
        String url = String.format("%s%s", BASE_URL, uri);
        String res = HttpClientUtils.httpGet(url, headerMap);
        return parseToComplaintHistoryList(param.getComplaintId(), res);
    }

    /**
     * 解析微信客诉协商历史
     *
     * @param complaintId 投诉单号
     * @param res         微信客诉协商历史api 返回值
     * @return 协商历史数据库实体列表
     */
    private List<ComplaintHistoryDO> parseToComplaintHistoryList(String complaintId, String res) {
        // 构造返回参数
        List<ComplaintHistoryDO> complaintHistoryDOList = new ArrayList<>();
        JSONObject jsonObject = JSONObject.parseObject(res);
        JSONArray dataArray = jsonObject.getJSONArray("data");
        if (dataArray.isEmpty()) {
            log.warn("投诉单号{}拉取客诉协商历史列表为空", complaintId);
            return complaintHistoryDOList;
        }
        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject dataObject = dataArray.getJSONObject(i);
            // 初始化其属性
            complaintHistoryDOList.add(new ComplaintHistoryDO().setComplaintId(complaintId).setUuid(dataObject.getString("log_id"))
                    .setPicture(getWechatPicture_History(dataObject, complaintId)).setContent(dataObject.getString("operate_details"))
                    .setSender(!Objects.equals(COMPLAINANT, dataObject.getString("operator")) ? SYSTEM : COMPLAINANT).setAdminFlag(!Objects.equals(COMPLAINANT, dataObject.getString("operator")))
                    .setSendTime(LocalDateTime.parse(dataObject.getString("operate_time"), DateTimeFormatter.ISO_DATE_TIME))
            );
        }
        return complaintHistoryDOList;
    }

    /**
     * 处理微信客诉文件 - 客诉
     *
     * @param dataObject  微信客诉文件对象
     * @param complaintId 投诉单号
     * @return ossUrl拼接的字符串
     */
    private String getWechatPicture(JSONObject dataObject, String complaintId) {
        JSONArray mediaArray = dataObject.getJSONArray("complaint_media_list");
        if (Objects.isNull(mediaArray) && mediaArray.isEmpty()) {
            return null;
        }
        StringBuilder pictureBuilder = new StringBuilder();
        for (int i = 0; i < mediaArray.size(); i++) {
            JSONObject mediaObject = mediaArray.getJSONObject(i);
            JSONArray mediaUrlArray = mediaObject.getJSONArray("media_url");
            for (int j = 0; j < mediaUrlArray.size(); j++) {
                String[] split = mediaUrlArray.getString(j).split("/");
                String ossUrl = getWeChatImageApi(complaintId, split[split.length - 1]);
                if (Objects.nonNull(ossUrl)) {
                    pictureBuilder.append(ossUrl).append(";");
                }
            }
        }
        int length = pictureBuilder.length();
        if (length > 0) {
            pictureBuilder.delete(length - 1, length);
        }
        return pictureBuilder.toString();
    }

    /**
     * 处理微信客诉文件 - 协商历史
     *
     * @param dataObject  微信协商历史
     * @param complaintId 投诉单号
     * @return ossUrl拼接的字符串
     */
    private String getWechatPicture_History(JSONObject dataObject, String complaintId) {
        JSONObject mediaObject = dataObject.getJSONObject("complaint_media_list");
        if (Objects.isNull(mediaObject)) {
            return null;
        }
        StringBuilder pictureBuilder = new StringBuilder();
        JSONArray mediaUrlArray = mediaObject.getJSONArray("media_url");
        for (int j = 0; j < mediaUrlArray.size(); j++) {
            String[] split = mediaUrlArray.getString(j).split("/");
            String ossUrl = getWeChatImageApi(complaintId, split[split.length - 1]);
            if (Objects.nonNull(ossUrl)) {
                pictureBuilder.append(ossUrl).append(";");
            }
        }
        int length = pictureBuilder.length();
        if (length > 0) {
            pictureBuilder.delete(length - 1, length);
        }
        return pictureBuilder.toString();
    }

    /**
     * 下载微信客诉图片
     * 1.微信下载客诉附件图片
     * 2.上传到oss
     * 3.返回 ossUrl
     *
     * @param complaintId
     * @param pictureId
     * @return
     */
    private String getWeChatImageApi(String complaintId, String pictureId) {
        String uri = String.format(COMPLAINT_PICTURE, pictureId);
        String url = String.format("%s%s", BASE_URL, uri);
        try {
            String authorization = null;
            try {
                authorization = getHttpAuthorization(uri, "GET", "");
            } catch (Exception e) {
                log.error("投诉单号{}签名生成失败", complaintId, e);
                return null;
            }
            Map<String, Object> headerMap = getHeaderMap_Get(authorization);
            InputStream inputStream = HttpClientUtils.httpGetFile(url, headerMap);
            return OssFileUtils.uploadByAliYun(inputStream, getOssConfig(), String.format("complaint/Wechat-picture-%s", UUID.randomUUID()), "image/jpeg", OssFileUtils.IMAGE);
        } catch (Exception e) {
            log.error("投诉单号{}图片处理失败", complaintId, e);
            return null;
        }
    }

    /**
     * 微信客诉 - 变更客诉状态为已完成
     *
     * @param param 客诉反馈处理完成参数
     * @return
     */
    @Override
    public Boolean completeApi(ComplaintCompleteParam param) {
        WeixinPayConfig weixinPayConfig = weixinPayConfigService.getByAccountId(param.getBrandId(), 2);
        if (Objects.isNull(weixinPayConfig)) {
            throw new BaseException(String.format("%s微信品牌配置为空", param.getBrandId()));
        }
        String uri = String.format(COMPLETE_COMPLAINT_URL, param.getComplaintId());
        String bodyStr = getCompleteParamBodyStr(weixinPayConfig.getPartner());
        String authorization = null;
        try {
            authorization = getHttpAuthorization(uri, "POST", bodyStr);
        } catch (Exception e) {
            log.error("投诉单号{}签名生成失败", param.getComplaintId(), e);
            return false;
        }
        Map<String, Object> headerMap = getHeaderMap_Post(authorization);

        String url = String.format("%s%s", BASE_URL, uri);
        HttpClientUtils.httpPost(url, headerMap, bodyStr);
        return true;
    }

    /**
     * 生成签名
     *
     * @param uri        功能接口二级路径
     * @param httpMethod Http请求方法
     * @param bodyStr    请求体参数
     * @return 签名
     * @throws Exception
     */
    private String getHttpAuthorization(String uri, String httpMethod, String bodyStr) throws Exception {
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String nonceStr = WxV3Utils.generateNonceStr(); // 随机字符串
        String apiClientKeyPath = wxMchConfig.getPrivateKeyPath();
        String mchid = wxMchConfig.getMchId();
        String certSerialNo = wxMchConfig.getMerchantSerialNumber();
        String signature = WxV3Utils.generateSignature(httpMethod, uri, timestamp, nonceStr, bodyStr, apiClientKeyPath);
        return String.format("%s mchid=\"%s\",nonce_str=\"%s\",signature=\"%s\",timestamp=\"%s\",serial_no=\"%s\"", "WECHATPAY2-SHA256-RSA2048", mchid, nonceStr, signature, timestamp, certSerialNo);
    }

    /**
     * 微信Get请求头生成
     *
     * @param authorization 签名认证信息
     * @return 微信Get请求头信息
     */
    @NotNull
    private Map<String, Object> getHeaderMap_Get(String authorization) {
        Map<String, Object> headerMap = new HashMap<>();
        headerMap.put("Authorization", authorization);
        headerMap.put("Accept", "application/json");
        return headerMap;
    }

    /**
     * 微信post请求头生成
     *
     * @param authorization 签名认证信息
     * @return 微信post请求头信息
     */
    @NotNull
    private Map<String, Object> getHeaderMap_Post(String authorization) {
        Map<String, Object> headerMap = new HashMap<>();
        headerMap.put("Authorization", authorization);
        headerMap.put("Accept", "application/json");
        headerMap.put("Content-Type", "application/json");
        return headerMap;
    }

    /**
     * 构造客诉回复的body参数json串
     *
     * @return 客诉回复body信息
     */
    private String getResponseParamBodyStr(String complaint_mchId, String response_content) {
        JSONObject body = new JSONObject();
        // 投诉单对应的被诉商户号
        body.put("complainted_mchid", complaint_mchId);
        // 具体的投诉处理方案，限制200个字符以内
        body.put("response_content", response_content);
        //todo 回复图片，跳转链接，跳转小程序 暂不接入  有需要详见 ： https://pay.weixin.qq.com/doc/v3/merchant/4012467254
        return JSON.toJSONString(body);
    }

    /**
     * 反馈客诉完成参数
     *
     * @param complaint_mchId 投诉商户号
     * @return 反馈客诉完成body参数
     */
    private String getCompleteParamBodyStr(String complaint_mchId) {
        JSONObject body = new JSONObject();
        // 投诉单对应的被诉商户号
        body.put("complainted_mchid", complaint_mchId);
        return JSON.toJSONString(body);
    }

    /**
     * 解密投诉人手机号
     *
     * @throws BadPaddingException
     * @throws IOException
     */
    public String parsePhone(String phoneSecret) {
        try {
            return WxV3Utils.rsaDecryptOAEP(phoneSecret, wxMchConfig);
        } catch (Exception e) {
            log.error("微信解密手机号失败", e);
        }
        return null;
    }

    /**
     * 微信客诉 - 平台主动拉取客诉
     *
     * @param param 客诉拉取参数
     * @return 客诉数据库实体列表
     */
    @Override
    public List<ComplaintDO> pullComplaintApi(ComplaintPullParam param) {
        WeixinPayConfig weixinPayConfig = weixinPayConfigService.getByAccountId(param.getBrandId(), 2);
        if (Objects.isNull(weixinPayConfig)) {
            log.warn(String.format("%s微信品牌配置为空,拉取客诉列表失败", param.getBrandId()));
            return new ArrayList<ComplaintDO>();
        }
        String begin_date = LocalDateTime.parse(param.getStartTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        String end_date = LocalDateTime.parse(param.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        String uri = String.format("%s?begin_date=%s&end_date=%s&complainted_mchid=%s&limit=%d&offset=%d", PULL_COMPLAINT_URL,
                begin_date, end_date, weixinPayConfig.getPartner(), param.getLimit(), param.getOffset());
        String authorization = null;
        try {
            authorization = getHttpAuthorization(uri, "GET", "");
        } catch (Exception e) {
            log.error("签名生成失败", e);
            return new ArrayList<ComplaintDO>();
        }
        String url = String.format("%s%s", BASE_URL, uri);
        // 进行http调用客户端
        Map<String, Object> headerMap = getHeaderMap_Get(authorization);
        String res = HttpClientUtils.httpGet(url, headerMap);
        return parseToComplaintDO(param.getBrandId(), res);
    }

    private List<ComplaintDO> parseToComplaintDO(Integer brandId, String res) {
        List<ComplaintDO> complaintDOList = new ArrayList<>();
        JSONObject jsonObject = JSONObject.parseObject(res);
        JSONArray dataArray = jsonObject.getJSONArray("data");
        if (dataArray.isEmpty()) {
            log.warn("拉取客诉列表为空");
            return complaintDOList;
        }
        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject complaintObject = dataArray.getJSONObject(i);
            LocalDateTime complaintTime = LocalDateTime.parse(complaintObject.getString("complaint_time"), DateTimeFormatter.ISO_DATE_TIME);
            JSONArray complaintOrderInfoList = complaintObject.getJSONArray("complaint_order_info");
            //todo 暂时只取列表第一笔，多笔的情况是哪种未知
            JSONObject orderInfoJSONObject = complaintOrderInfoList.getJSONObject(0);
            String complaintId = complaintObject.getString("complaint_id");
            String picture = getWechatPicture(complaintObject, complaintId);
            String orderNO = orderInfoJSONObject.getString("out_trade_no");
            complaintDOList.add(
                    new ComplaintDO().setBrandId(brandId)
                            .setComplaintId(complaintId)
                            .setComplaintTime(complaintTime)
                            .setPlatform(PlatformEnum.WECHAT.getCode())
                            .setOrderMoney(orderInfoJSONObject.getInteger("amount"))
                            .setDescription(complaintObject.getString("complaint_detail"))
                            .setPicture(picture)
                            .setPhone(parsePhone(complaintObject.getString("payer_phone")))
                            .setOrderNO(orderNO)
                            .setStatus(ComplaintStatusEnum.NEW.getCode())
            );
        }
        return complaintDOList;
    }
}
